import { TinyEmitter } from "tiny-emitter";
import {TableCardList} from "./TableCardList";
import {IndexedDBTable} from "./IndexedDBTable";
import {AppTinyEmitter} from "../AkabaVendor/AppTinyEmitter";

export namespace AppDB {
    export interface IEvtArg extends AppTinyEmitter.IBaseEvtMap {
        open_error: [ Event ],
        open_success: [ AppDB.IEvtOpenSuccess ],
        upgrade_end: [ AppDB.IEvtUpgradeEnd ],
    }
    export interface IEvtOpenSuccess extends Event {
        target: IDBOpenDBRequest
    }
    export interface IEvtUpgradeEnd extends IDBVersionChangeEvent {
        target: IDBOpenDBRequest
    }
}

export class AppDB extends AppTinyEmitter<AppDB.IEvtArg>  {
    private static instance: AppDB;
    public static readonly DB_NAME = "speed_dial_akaba";
    public static readonly DB_VERSION_STR: string = "1.0.0"; // 必须为整型
    public static get DB_VERSION(): number {
        const strList = AppDB.DB_VERSION_STR.split(".");
        return parseInt(strList.map((item: string) => {
            return item.padStart(2, "0");
        }).join(""));
    }
    public db?: IDBDatabase;
    public readonly evtEmitterId = "app database";

    public get tableCardList(): TableCardList | undefined {
        return this.db && TableCardList.getInstance(this.db);
    };

    private constructor() {
        super();
        this.open();
    }
    protected open():void {
        const request = window.indexedDB.open(AppDB.DB_NAME, AppDB.DB_VERSION);
        request.addEventListener("error", (err) => {
            this.emit("open_error", err);
        });
        request.addEventListener("success", (evt: Event) => {
            const openSuccessEvt = evt as AppDB.IEvtOpenSuccess;
            this.db = openSuccessEvt.target.result;
            this.emit("open_success", openSuccessEvt);
        });
        request.addEventListener("upgradeneeded", (evt: IDBVersionChangeEvent) => {
            const upgradeEndEvt = evt as AppDB.IEvtUpgradeEnd;
            this.db = upgradeEndEvt.target.result;
            this.installTables(upgradeEndEvt);
            this.emit("upgrade_end", upgradeEndEvt);
        });
    }
    protected installTables(evt: AppDB.IEvtUpgradeEnd): void {
        TableCardList.getInstance(this.db as IDBDatabase, "create");
    }

    public getDataBase(): Promise<IDBDatabase> {
        if (this.db) {
            return Promise.resolve(this.db);
        }
        return new Promise((resolve, reject) => {
            this.on("open_success", () => {
               resolve(this.db as IDBDatabase);
            });
            this.on("open_error", (err) => {
                reject(err);
            });
            this.open();
        });
    }
    public static getInstance(): AppDB {
        if (!this.instance) {
            this.instance = new AppDB();
        }
        return this.instance;
    }
}

export const appDB = AppDB.getInstance();
